<?php
//+----------------------------------------------------------------------
//|版权所有：山西创泰网络科技有限公司
//+----------------------------------------------------------------------
//|Author: dtt Date: 2021/6/9 0009 Time: 16:19
//+----------------------------------------------------------------------

namespace services;

use app\services\sms\SmsRecordService;
use exceptions\SmsException;
use think\Exception;
use think\facade\Config;
use function EasyWeChat\Kernel\Support\get_client_ip;

class SmsService
{
    // 接口地址
    const HOST = 'http://api.1cloudsp.com/';

    // 个人短信
    const SINGLE = 'api/v2/single_send';

    // 群发
    const GROUP = 'api/v2/send';

    // 查询短信状态
    const STATUS = 'report/status';

    // 签名列表
    const SIGN_LIST = 'query/signlist';

    // 创建签名
    const ADD_SIGN = 'open/api/addSign';

    // 修改签名
    const EDIT_SIGN = 'open/api/modifySign';

    // 模板列表
    const TEMP_LIST = 'query/templatelist';

    // 添加、修改模板
    const SAVE_TEMP = 'open/api/addTemplate';

    // 查询余额
    const BALANCE = 'query/account';

    private $baseParam = [];

    /**
     * OneCloudSPService constructor.
     *
     * @param string $type
     *
     * @return bool|void
     * @throws Exception
     */
    public function __construct()
    {
        $this->baseParam   = [
            'accesskey' => sysconfig('sms_cryun_accesskey'),
            'secret'    => sysconfig('sms_cryun_secret'),
        ];
        $this->templateIds = Config::get('sms.stores.cryun.template_id', []);

        $this->sign = Config::get('sms.stores.cryun.sign', []);;
        if (!$this->sign) {
            throw new SmsException('请配置创瑞云签名！');
        }
    }

    /**
     * 提取模板code
     *
     * @param string $templateId
     *
     * @return null
     */
    protected function getTemplateCode(string $templateId)
    {
        return ((string)$this->templateIds[$templateId]) ?? null;
    }

    /**
     * Description: 发送个人验证码
     * Function sendVerifyCode
     *
     * @param string $sign
     * @param string $mobile
     * @param array  $content
     * @param int    $templateId
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:31
     */
    public function sendVerifyCode(string $mobile, string $code)
    {
        $data               = [
            'mobile'  => $mobile,
            'content' => $code . '##' . sysconfig('verify_expire_time', 5)
        ];
        $data['templateId'] = $this->getTemplateCode('VERIFICATION_CODE');
        return $this->sendRequest(self::SINGLE, $data);
    }


    /**
     * Description: 发送群消息
     * Function send_sms
     *
     * @param string $mobile
     * @param string $content
     * @param string $data
     * @param string $templateId 模板id
     * @param string $scheduleSendTime 定时时间
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 16:42
     */
    public function sendGroupCode($mobile, $content, $data, $templateId = '', $scheduleSendTime = '')
    {
        return $this->sendRequest(self::GROUP, compact('mobile', 'content', 'data', 'templateId', 'scheduleSendTime'));
    }

    /**
     * Description: 获取短信状态
     * Function getSendStatus
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:31
     */
    public function getSendStatus()
    {
        return $this->sendRequest(self::STATUS);
    }

    /**
     * Description: 短信签名查询接口
     * Function getSignatureList
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:31
     */
    private function getSignatureList(string $signId)
    {
        $data = $this->sendRequest(self::SIGN_LIST);
        return array_values(array_filter($data['data'], function ($item) use ($signId) {
            return $item['signId'] == $signId && $item['applyStatus'] == 2;
        }))[0];
    }

    /**
     * Description: 添加签名接口
     * Function createSignature
     *
     * @param string $description
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:31
     */
    public function createSignature(string $description)
    {
        return $this->sendRequest(self::ADD_SIGN, compact('description'));
    }

    /**
     * Description: 修改签名
     * Function updateSignature
     *
     * @param int    $id
     * @param string $description
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:32
     */
    public function updateSignature(int $id, string $description = "")
    {
        return $this->sendRequest(self::EDIT_SIGN, compact('id', 'description'));
    }

    /**
     * Description: 获取模板列表
     * Function get_template_list
     * return eq:{
     *      code: "0",
     *      msg: "SUCCESS",
     *      "data": [{
     *          "templateId": 1,
     *          "template": "{1}你好：您的订单已经出库，请注意查收",
     *          "customerId": 10000,
     *          "applyStatus": 2, // 审核状态 1：未审核 2：审核通过 3：审核不通过
     *          "categoryId": 2 // 短信类别 1 验证码 2 通知&订单 3 营销
     *      },
     *      {
     *          "templateId": 2,
     *          "template": "你的验证码是：{1}",
     *          "customerId": 10000,
     *          "applyStatus": 2,
     *          "categoryId": 1
     *      }]
     * }
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:32
     */
    public function getTemplateList(string $tempId)
    {
        $data = $this->sendRequest(self::TEMP_LIST)['data'] ?? [];
        return array_values(array_filter($data, function ($item) use ($tempId) {
            return $item['applyStatus'] == 2 && $item['templateId'] == $tempId;
        }));
    }

    /**
     * Description: 创建模板
     * Function createTemplate
     *
     * @param string $templateName 模板名称
     * @param string $categoryId   1 - 验证码,2 - 通知&订单,3 - 营销
     * @param string $template     短信模板，采用utf8编码
     * @param string $description  简单描述使用场景
     * @param int    $id           模板id, 如果是编辑需要传参
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:28
     */
    public function createTemplate(string $templateName, int $categoryId, string $template, string $description, int $id)
    {
        $param = compact('templateName', 'categoryId', 'template', 'description');
        $id && $param['id'] = $id;
        return $this->sendRequest(self::SAVE_TEMP, $param);
    }

    /**
     * Description: 短信余额查询
     * Function account
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:30
     */
    public function account()
    {
        return $this->sendRequest(self::BALANCE, []);
    }

    /**
     * 获取发送状态
     *
     * @param array $recordIds
     *
     * @return array|mixed
     */
    public function getStatus(array $recordIds)
    {
        // $data['record_id'] = json_encode($recordIds);
        return $this->sendRequest(self::STATUS);
    }

    /**
     * Description: 发送请求
     * Function send_request
     *
     * @param string $url
     * @param array  $params
     *
     * @return mixed
     * @throws Exception
     * @author: dtt
     * @date  : 2021/6/9 0009
     * @time  : 17:32
     */
    private function sendRequest(string $url, array $params = [], string $method = 'post')
    {
        $headers = [
            "Content-Type:application/x-www-form-urlencoded",
        ];

        if (is_null($params['templateId'])) {
            throw new SmsException('无效模板id');
        }
        $url = self::HOST . $url;

        $params = array_merge($params, $this->baseParam);

        $result = HttpService::request($url, $method, http_build_query($params, null), $headers);

        /** @var SmsRecordService $service */
        $recordServices = app()->make(SmsRecordService::class);
        $recordServices->save([
            'uid'        => $this->baseParam['accesskey'],
            'phone'      => $params['mobile'],
            'content'    => $params['content'] ?? '',
            'add_time'   => time(),
            'add_ip'     => get_client_ip(),
            'template'   => $params['templateId'],
            'record_id'  => $result['smUuid'] ?? '',
            'resultcode' => $result['code']
        ]);
        if ((int)$result['code'] != 0) {
            return self::errcode($result['code']);
        }
        return $result;
    }

    private function send_request($url, $params = '')
    {
        $headers = [
            "Content-Type:application/x-www-form-urlencoded",
        ];

        if (is_array($params)) {
            $params = http_build_query($params, null);
        }

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        $result = curl_exec($ch);
        curl_close($ch);

        return json_decode($result);
    }

    private static function errCode(int $code)
    {
        return [
                9001  => '签名格式不正确',
                9002  => '参数未赋值',
                9003  => '手机号码格式不正确',
                9006  => '用户accesskey不正确',
                9007  => 'IP白名单限制',
                9009  => '短信内容参数不正确',
                9010  => '用户短信余额不足',
                9011  => '用户帐户异常',
                9012  => '日期时间格式不正确',
                9013  => '不合法的语音验证码，4~8位的数字',
                9014  => '超出了最大手机号数量',
                9015  => '不支持的国家短信',
                9016  => '无效的签名或者签名ID',
                9017  => '无效的模板ID',
                9018  => '单个变量限制为1-20个字',
                9019  => '内容不可以为空',
                9021  => '主叫和被叫号码不能相同',
                9022  => '手机号码不能为空',
                9023  => '手机号码黑名单',
                9024  => '手机号码超频',
                10001 => '内容包含敏感词',
                10002 => '内容包含屏蔽词',
                10003 => '错误的定时时间',
                10004 => '自定义扩展只能是数字且长度不能超过4位',
                10005 => '模版类型不存在',
                10006 => '模版和内容不匹配'
            ][$code] ?? '未知错误';
    }

}